import { addListReturnRemove, promisify } from "../../libs/util";
import phera from "../../const/phera";
import { okmsg, failmsg } from "../../const/msg";

/**
 * 设备插件基类
 * @public
 */
class Peripheral {

  constructor() {
    this.available = false;
    this.discovering = false;
    this.connected = false;
    this.connectedDeviceIds = [];
  }
  /**
   * 启动插件
   * @public
   * @abstract
   * @returns {Promise<*>}
   */
  start() {
    throw new Error('Method not implemented');
  }

  /**
   * 开始扫描设备列表
   * @private
   */
  async discovery() {
    this.notifyDeviceFound();

    let { discovering } = await this.getBluetoothAdapterState();
    if (!discovering) {
      return await (promisify(phera.startBluetoothDevicesDiscovery))();
    } else {
      return okmsg;
    }
  }

  stopDiscovery() {
    return promisify(phera.stopBluetoothDevicesDiscovery)();
  }


  notifyBluetoothAdapterStateChange() {
    phera.onBluetoothAdapterStateChange(res => {
      console.log('[notifyBluetoothAdapterStateChange]', res);
      let { available, discovering } = res;
      this.available = available;
      this.discovering = discovering;

      if (available) {
        console.log('蓝牙已打开');
      } else {
        this.currentDevice = null;
        console.log('蓝牙已关闭');
      }
    });
  }

  notifyConnectionStateChange() {
    phera.onBLEConnectionStateChange(res => {
      console.log('[onBLEConnectionStateChange]', res);
      let { deviceId, connected } = res;
      this.connected = connected;
    });
  }

  stopDiscovery() {
    return promisify(phera.stopBluetoothDevicesDiscovery)();
  }

  /**
   * 监听发现的设备
   * @private
   * @abstract
   * @param {Function} cb 回调函数，参数未设备列表
   */
  notifyDeviceFound(cb) {
    phera.onBluetoothDeviceFound((res) => {
      console.log('[Peripheral.onBluetoothDeviceFound]', res);
    });
  }

  /**
   * 停止扫描设备
   * @abstract
   * @private
   */
  scanStop() {
    throw new Error('Method not implemented');
  }

  /**
   * 连接设备
   * @private
   * @param {String} deviceId 设备Id
   * @returns {Promise<*>}
   */
  connect(deviceId) {
    return promisify(phera.createBLEConnection)({ deviceId })
      .then(res => {
        this.connectedDeviceIds.push(deviceId);
        return Promise.resolve(res);
      });
  }

  disconnect(deviceId) {

  }

  /**
   * 获得设备特征值
   * @private
   */
  getConnectedBluetoothDevices() {
    return promisify(phera.getConnectedBluetoothDevices)();
  }

  getCurrentServices() {
    // serviceId: "0000FFE0-0000-1000-8000-00805F9B34FB",
    // readCharacteristicId: "0000FFE1-0000-1000-8000-00805F9B34FB",
    // writeCharacteristicId: "0000FFE3-0000-1000-8000-00805F9B34FB"
    return {
      serviceId: null,
      readCharacteristicId: null,
      writeCharacteristicId: null
    };
  }

  /**
   * 监听设备数值变化
   * @public
   * @param {Function} cb
   * @returns {Function} offFun
   */
  onDataChange(cb) {
    return this.addEvent('__onDataChange', cb);
  }

  /**
   * 检测特征值变化
   * @private
   */
  onCharacteristicValueChange() {
    phera.onBLECharacteristicValueChange(res => {
      // const { characteristicId, value } = res;
      this.getEvents('__onDataChange').forEach(cb => cb(res));
    });
  }

  /**
   * 监听特征值变化
   * @private
   */
  notifyCharacteristicValueChange(rep) {
    phera.notifyBLECharacteristicValueChange();
  }

  /**
   * 停止插件
   * @public
   * @abstract
   */
  stop() {
    this.running = false;
  }

  /**
   * 销毁插件
   * @private
   */
  dispose() {
    this.disposed = true;
    this.connected = false;

    this.connectedDeviceIds.forEach(deviceId => {
      phera.closeBLEConnection({ deviceId });
    });

    this.events && Object.keys(this.events).forEach(key => {
      this.events[key] = [];
    });
  }

  /**
   * @private
   */
  getBluetoothAdapterState() {
    return promisify(phera.getBluetoothAdapterState)();
  }

  /**
   * 添加事件
   * @private
   * @param {String} type 
   * @param {Function} cb 
   * @returns {Function} 移除事件
   */
  addEvent(type, cb) {
    if (!this.events) {
      this.events = {};
    }
    if (!this.events[type]) {
      this.events[type] = [];
    }
    return addListReturnRemove(cb, this.events[type]);
  }

  /**
   * 获取添加事件
   * @private
   * @param {String} type
   * @returns {Array}
   */
  getEvents(type) {
    if (!this.events) return [];
    return this.events[type];
  }

}

export default Peripheral;
